<template>
  <div ref="boxRef" class="chart-box sales-box">
    <div class="chart-header">
      <h3>
        <span class="title-icon">|</span>
        <span>商家销售统计</span>
      </h3>
      <button class="fullscreen-btn" @click="toggleFullscreen">⛶</button>
    </div>
    <div ref="chartRef" class="chart"></div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import { subscribeToChart } from '@/services/dataHub';

const props = defineProps<{ isDarkTheme: boolean }>();

const chartRef = ref<HTMLElement | null>(null);
const boxRef = ref<HTMLElement | null>(null);
let chart: echarts.ECharts | null = null;
let resizeHandler: (() => void) | null = null;
let fullscreenTimer: number | null = null;
let highlightTimer: number | null = null;
let highlightIndex = 0;
const HIGHLIGHT_INTERVAL = 3500;
let pageTimer: number | null = null;
const PAGE_INTERVAL = 3000;
let pageIndex = 0;
let totalPages = 0;
const PAGE_SIZE = 5;
let currentPageItems: SellerItem[] = [];
type SellerItem = { name: string; value: number };
let originalData: SellerItem[] = [];
let unsubscribe: (() => void) | null = null;

type GradientStop = { offset: number; color: string };

const GRADIENT_STOPS: Record<'high' | 'medium' | 'base', GradientStop[]> = {
  high: [
    { offset: 0, color: '#0FAC30' },
    { offset: 0.6, color: '#2BCE50' },
    { offset: 1, color: '#4EF677' },
  ],
  medium: [
    { offset: 0, color: '#2D75C0' },
    { offset: 0.5, color: '#28A7D0' },
    { offset: 1, color: '#23E0E3' },
  ],
  base: [
    { offset: 0, color: '#5b5fd8' },
    { offset: 0.5, color: '#8e7dd8' },
    { offset: 1, color: '#c084fc' },
  ],
};

const buildGradient = (value: number) => {
  const stops = value >= 300 ? GRADIENT_STOPS.high : value >= 200 ? GRADIENT_STOPS.medium : GRADIENT_STOPS.base;
  return new echarts.graphic.LinearGradient(0, 0, 1, 0, stops);
};

const decodeText = (text: string) => {
  try {
    return decodeURIComponent(escape(text));
  } catch (error) {
    return text;
  }
};

const stopHighlightLoop = () => {
  if (highlightTimer) {
    window.clearInterval(highlightTimer);
    highlightTimer = null;
  }
};

const runHighlightStep = () => {
  if (!chart || !currentPageItems.length) return;
  const targetIndex = highlightIndex % currentPageItems.length;
  chart.dispatchAction({ type: 'downplay', seriesIndex: 0 });
  chart.dispatchAction({ type: 'highlight', seriesIndex: 0, dataIndex: targetIndex });
    // chart.dispatchAction({ type: 'showTip', seriesIndex: 0, dataIndex: targetIndex }); // 禁止自动显示tooltip
  highlightIndex = (targetIndex + 1) % currentPageItems.length;
};

const startHighlightLoop = () => {
  stopHighlightLoop();
  if (!chart || !currentPageItems.length) return;
  highlightIndex = 0;
  runHighlightStep();
  highlightTimer = window.setInterval(runHighlightStep, HIGHLIGHT_INTERVAL);
};

const handleChartMouseOver = () => {
  stopHighlightLoop();
};

const handleChartMouseOut = () => {
  startHighlightLoop();
};

const bindChartHoverEvents = () => {
  if (!chart) return;
  chart.off('mouseover', handleChartMouseOver as any);
  chart.off('mouseout', handleChartMouseOut as any);
  chart.on('mouseover', handleChartMouseOver as any);
  chart.on('mouseout', handleChartMouseOut as any);
};

const stopPageLoop = () => {
  if (pageTimer) {
    window.clearInterval(pageTimer);
    pageTimer = null;
  }
};

const startPageLoop = () => {
  stopPageLoop();
  if (totalPages <= 1) return;
  pageTimer = window.setInterval(() => {
    pageIndex = (pageIndex + 1) % totalPages;
    updateChartOption();
  }, PAGE_INTERVAL);
};

const getPageItems = () => {
  if (!originalData.length) {
    totalPages = 0;
    return [] as SellerItem[];
  }

  totalPages = Math.max(1, Math.ceil(originalData.length / PAGE_SIZE));
  if (pageIndex >= totalPages) {
    pageIndex = 0;
  }

  const start = pageIndex * PAGE_SIZE;
  return originalData.slice(start, start + PAGE_SIZE);
};

const disposeChart = () => {
  stopHighlightLoop();
  stopPageLoop();
  if (chart && !chart.isDisposed()) {
    chart.dispose();
  }
  chart = null;
};

// 获取商家销售数据（改用 WebSocket）
function setupSellerDataSubscription() {
  unsubscribe = subscribeToChart('seller', (data: any) => {
    const list: SellerItem[] = Array.isArray(data)
      ? data
      : Array.isArray(data?.data)
        ? data.data
        : [];
    const mapped = list
      .map((item) => ({
        name: decodeText(item.name),
        value: Number(item.value) || 0,
      }))
      .filter((item) => item.name);

    const sorted = [...mapped].sort((a, b) => a.value - b.value);
    // 只在数据长度变化时重置 pageIndex
    const oldLen = originalData.length;
    originalData = sorted;
    if (oldLen !== sorted.length) {
      pageIndex = 0;
    }
    updateChartOption();
  });
}

// 更新图表配置
function updateChartOption() {
  if (!chart) return;

  const pageItems = getPageItems();
  const items = [...pageItems].sort((a, b) => a.value - b.value);
  currentPageItems = items;

  if (!items.length) {
    chart.setOption({
      backgroundColor: 'transparent',
      series: [],
    });
    stopHighlightLoop();
    stopPageLoop();
    return;
  }

  const names = items.map((item) => item.name);
  const values = items.map((item) => item.value);
  const maxValue = Math.max(...values, 0) + 30;

  const option: EChartsOption = {
    backgroundColor: 'transparent',
    tooltip: {
      trigger: 'item',
      backgroundColor: 'rgba(0,0,0,0.85)',
      borderColor: '#4a5568',
      textStyle: { color: '#fff' },
      alwaysShowContent: false,
      triggerOn: 'mousemove',
      showDelay: 0,
      hideDelay: 100,
    },
    grid: { top: '8%', left: '3%', right: '3%', bottom: '8%', containLabel: true },
    xAxis: {
      type: 'value',
      axisLine: { show: false },
      axisLabel: { color: '#8492a6', fontSize: 11 },
      splitLine: { lineStyle: { color: '#233a4d', type: 'dashed' } },
      splitArea: { show: false },
      max: maxValue,
    },
    yAxis: {
      type: 'category',
      data: names,
      axisLine: { lineStyle: { color: '#2f4554' } },
      axisLabel: { color: '#8492a6', fontSize: 11 },
      axisTick: { show: false },
      splitArea: { show: false },
    },
    series: [
      {
        type: 'bar',
        data: values,
        barWidth: '45%',
        itemStyle: {
          borderRadius: [0, 10, 10, 0],
          color: (params: any) => buildGradient(Number(params.value) || 0),
          shadowBlur: 12,
          shadowColor: 'rgba(0, 0, 0, 0.25)',
          shadowOffsetX: 2,
          shadowOffsetY: 2,
        },
        label: {
          show: true,
          position: 'right',
          color: '#fff',
          fontSize: 13,
          fontWeight: 600,
        },
      },
    ],
  };

  chart.setOption(option);
  startHighlightLoop();
  startPageLoop();
}

const initChart = () => {
  if (!chartRef.value) return;
  disposeChart();
  chart = echarts.init(chartRef.value);
  bindChartHoverEvents();

  if (originalData.length) {
    updateChartOption();
  }

  if (!resizeHandler) {
    resizeHandler = () => chart?.resize();
    window.addEventListener('resize', resizeHandler);
  }
};

const toggleFullscreen = () => {
  const box = boxRef.value;
  if (!box) return;
  const button = box.querySelector('.fullscreen-btn') as HTMLButtonElement | null;

  if (!box.classList.contains('fullscreen')) {
    box.classList.add('fullscreen');
    if (button) button.textContent = '✕';
    fullscreenTimer = window.setTimeout(() => chart?.resize(), 300);
    window.addEventListener('keydown', escListener);
  } else {
    box.classList.remove('fullscreen');
    if (button) button.textContent = '⛶';
    fullscreenTimer = window.setTimeout(() => chart?.resize(), 300);
    window.removeEventListener('keydown', escListener);
  }
};

function escListener(e: KeyboardEvent) {
  if (e.key === 'Escape') {
    const box = boxRef.value;
    if (box && box.classList.contains('fullscreen')) {
      toggleFullscreen();
    }
  }
}

watch(
  () => props.isDarkTheme,
  () => {
    initChart();
  }
);

onMounted(() => {
  setupSellerDataSubscription();
  initChart();
});

onUnmounted(() => {
  if (unsubscribe) {
    unsubscribe();
  }
  if (resizeHandler) {
    window.removeEventListener('resize', resizeHandler);
  }
  if (fullscreenTimer) {
    window.clearTimeout(fullscreenTimer);
  }
  window.removeEventListener('keydown', escListener);
  disposeChart();
});
</script>
